﻿using System.Collections;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Text.Json.Serialization;
using Newtonsoft.Json;
using static Devonline.Core.Helper;

namespace Devonline.Core
{
    public static class TypeExtensions
    {
        /// <summary>
        /// 是否为可空类型
        /// TODO 在启用可空引用时待验证
        /// </summary>
        /// <param name="type">待判断的类型</param>
        /// <returns>判断结果</returns>
        public static bool IsNullable(this Type type)
        {
            return (!type.IsValueType) || (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>));
        }
        /// <summary>
        /// 获取类型的核心类型, 用于判断可空类型的基本类型
        /// TODO 在启用可空引用时待验证
        /// </summary>
        /// <param name="type">原始类型</param>
        /// <returns>核心类型</returns>
        public static Type GetCoreType(this Type type) => IsNullable(type) ? (Nullable.GetUnderlyingType(type) ?? type) : type;
        /// <summary>
        /// 获取泛型类型的泛型参数类型
        /// </summary>
        /// <param name="type">原始类型</param>
        /// <returns>泛型参数类型</returns>
        public static Type? GetGenericType(this Type type)
        {
            if (!type.IsGenericType)
            {
                Type? baseType = type.BaseType;

                do
                {
                    baseType = baseType?.BaseType;
                }
                while (baseType != null && baseType.BaseType != null && !baseType.IsGenericType);

                if (baseType != null && baseType.IsGenericType)
                {
                    type = baseType;
                }
            }

            if (type.IsGenericType)
            {
                return type.GenericTypeArguments?.FirstOrDefault()?.GetCoreType();
            }

            return type.GetCoreType();
        }
        /// <summary>
        /// get the most inner base type of a type
        /// </summary>
        /// <param name="type">type instance</param>
        /// <returns>the most inner type</returns>
        public static Type? GetBaseType(this Type type)
        {
            if (type?.BaseType != null)
            {
                return type.BaseType.GetBaseType();
            }

            return type;
        }
        /// <summary>
        /// to judge a type is from type or inherit from type 
        /// </summary>
        /// <param name="type"></param>
        /// <param name="from"></param>
        /// <returns>bool</returns>
        public static bool IsFromType(this Type type, Type from) => type.IsAssignableTo(from);
        /// <summary>
        /// to judge a type is from type or inherit from type 
        /// </summary>
        /// <param name="type"></param>
        /// <typeparam name="TType">from type 的类型参数</typeparam>
        /// <returns>bool</returns>
        public static bool IsFromType<TType>(this Type type) => type.IsAssignableTo(typeof(TType));
        /// <summary>
        /// 判断一个类型是否一个集合类型
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static bool IsCollection(this Type type) => type.IsCollectible || type.IsFromType<IEnumerable>();
        /// <summary>
        /// 判断一个类型是否泛型类型 
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static bool IsGenericType(this Type type)
        {
            if (type.IsGenericType)
            {
                return true;
            }

            if (type.BaseType == null)
            {
                return false;
            }

            return type.BaseType.IsGenericType();
        }
        /// <summary>
        /// 返回一个类型是否基本数据类型
        /// 基础数据类型是指语言内置的基本值类型的数据类型
        /// 也即 TypeCode 从 Boolean 到 Decimal 的
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static bool IsBasicType(this Type type) => Type.GetTypeCode(type) switch
        {
            >= TypeCode.Boolean and <= TypeCode.Decimal => true,
            _ => false
        };
        /// <summary>
        /// 返回一个类型是否是除 object 和 dynamic 以外的内置数据类型
        /// 这两种数据类型对于判断无意义
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static bool IsBuiltInType(this Type type) => Type.GetTypeCode(type) switch
        {
            >= TypeCode.Boolean and <= TypeCode.Decimal => true,
            TypeCode.String => true,
            _ => false
        };
        /// <summary>
        /// 返回一个类型是否简单类型
        /// 此处定义的简单类型指基本数据类型 + datetime + string 这两种可以在数据库中直接进行字段关系隐射的类型
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static bool IsSampleType(this Type type) => Type.GetTypeCode(type) switch
        {
            >= TypeCode.Boolean and <= TypeCode.String => true,
            _ => false
        };

        /// <summary>
        /// 获取对象上的显示名称 (Display 或 DisplayName 或 Description 特性的值)
        /// </summary>
        /// <param name="member">待获取对象</param>
        /// <returns>显示名称</returns>
        public static string GetDisplayName([DisallowNull] this MemberInfo member) => member.GetCustomAttribute<DisplayAttribute>()?.Name ?? member.GetCustomAttribute<DisplayNameAttribute>()?.DisplayName ?? member.GetCustomAttribute<DescriptionAttribute>()?.Description ?? member.Name;
        /// <summary>
        /// 通过当前类型的公开实例成员获取成员标注的 Display/DisplayName 特性的值
        /// </summary>
        /// <param name="type"></param>
        /// <param name="memberName"></param>
        /// <returns></returns>
        public static string? GetDisplayName([DisallowNull] this Type type, string memberName) => type.GetMember(memberName, BindingFlags.Public | BindingFlags.Instance)?.FirstOrDefault()?.GetDisplayName();
        /// <summary>
        /// 获取对象上的隐射到数据库的字段名字(Column 特性的 Name 值)
        /// </summary>
        /// <param name="member">待获取对象</param>
        /// <returns>字段名称</returns>
        public static string GetColumnName([DisallowNull] this MemberInfo member) => member.GetCustomAttribute<ColumnAttribute>()?.Name ?? member.Name;
        /// <summary>
        /// 获取对象上的隐射到数据库的字段名字(Table 特性的 Name 值)
        /// </summary>
        /// <param name="member">待获取对象</param>
        /// <returns>字段名称</returns>
        public static string GetTableName([DisallowNull] this MemberInfo member) => member.GetCustomAttribute<TableAttribute>()?.Name ?? member.Name;
        /// <summary>
        /// 获取类型字段设置的 json 序列化字段名
        /// </summary>
        /// <param name="type"></param>
        /// <param name="memberName"></param>
        /// <returns></returns>
        public static string? GetJsonPropertyName([DisallowNull] this Type type, string memberName)
        {
            var member = type.GetMember(memberName)?.FirstOrDefault();
            return member?.GetCustomAttribute<JsonPropertyAttribute>()?.PropertyName ?? member?.GetCustomAttribute<JsonPropertyNameAttribute>()?.Name ?? member?.Name;
        }

        /// <summary>
        /// 返回成员的真实类型
        /// </summary>
        /// <param name="member"></param>
        /// <returns></returns>
        public static Type GetMemberType([DisallowNull] this MemberInfo member) => member switch
        {
            PropertyInfo propertyInfo => propertyInfo.PropertyType,
            FieldInfo fieldInfo => fieldInfo.FieldType,
            Type type => type,
            _ => member.GetType()
        };

        /// <summary>
        /// 获取类型的实例
        /// </summary>
        /// <param name="type"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public static object? CreateInstance(this Type type, params object[] parameters) => Activator.CreateInstance(type, parameters);
        /// <summary>
        /// 反射调用类型的静态泛型方法
        /// </summary>
        /// <param name="type">调用类型</param>
        /// <param name="methodName">方法名</param>
        /// <param name="parameters">参数列表</param>
        /// <param name="returnValue">返回值</param>
        /// <param name="genericTypes">泛型类型</param>
        public static void InvokeGenericMethod(this Type type, string methodName, object[] parameters, out object? returnValue, params Type[] genericTypes)
        {
            returnValue = null;
            var methodInfo = type?.GetMethods().FirstOrDefault(x => x.IsGenericMethod && x.Name == methodName && x.GetParameters().Length == (parameters?.Length ?? 0));
            if (methodInfo != null)
            {
                returnValue = methodInfo.MakeGenericMethod(genericTypes).Invoke(null, parameters);
            }
        }
        /// <summary>
        /// 反射调用类型的静态泛型方法
        /// </summary>
        /// <typeparam name="T">返回值类型</typeparam>
        /// <param name="type">调用类型</param>
        /// <param name="methodName">方法名</param>
        /// <param name="parameters">参数列表</param>
        /// <param name="genericTypes">泛型类型</param>
        /// <returns>返回调用结果</returns>
        public static T? InvokeGenericMethod<T>(this Type type, string methodName, object[] parameters, params Type[] genericTypes) where T : class
        {
            var methodInfo = type?.GetMethods().FirstOrDefault(x => x.IsGenericMethod && x.Name == methodName && x.GetParameters().Length == (parameters?.Length ?? 0));
            if (methodInfo != null)
            {
                var returnValue = methodInfo.MakeGenericMethod(genericTypes).Invoke(null, parameters);
                if (returnValue != null)
                {
                    return (T)returnValue;
                }
            }

            return default;
        }
        /// <summary>
        /// 反射调用类型的泛型扩展方法
        /// 预处理调用者参数, 因此不需要传递调用者参数
        /// </summary>
        /// <param name="type">调用类型</param>
        /// <param name="methodName">方法名</param>
        /// <param name="caller">调用对象</param>
        /// <param name="parameters">参数列表</param>
        /// <param name="returnValue">返回值</param>
        /// <param name="genericTypes">泛型类型</param>
        public static void InvokeGenericMethod(this Type type, string methodName, object caller, object[] parameters, out object? returnValue, params Type[] genericTypes)
        {
            returnValue = null;
            var methodInfo = type?.GetTypeInfo().GetDeclaredMethods(methodName).FirstOrDefault(x => x.IsGenericMethod && x.GetParameters().Length == (parameters?.Length ?? 0) + 1);
            if (methodInfo != null)
            {
                var args = new List<object>
                {
                    caller
                };

                if (parameters.IsNotNullOrEmpty())
                {
                    args.AddRange(parameters);
                }

                returnValue = methodInfo.MakeGenericMethod(genericTypes).Invoke(caller, args.ToArray());
            }
        }
        /// <summary>
        /// 反射调用类型的泛型扩展方法
        /// 预处理调用者参数, 因此不需要传递调用者参数
        /// </summary>
        /// <typeparam name="T">返回值类型</typeparam>
        /// <param name="type">调用类型</param>
        /// <param name="methodName">方法名</param>
        /// <param name="caller">调用对象</param>
        /// <param name="parameters">参数列表</param>
        /// <param name="genericTypes">泛型类型</param>
        /// <returns>返回调用结果</returns>
        public static T? InvokeGenericMethod<T>(this Type type, string methodName, object caller, object[] parameters, params Type[] genericTypes) where T : class
        {
            var methodInfo = type?.GetTypeInfo().GetDeclaredMethods(methodName).FirstOrDefault(x => x.IsGenericMethod && x.GetParameters().Length == (parameters?.Length ?? 0) + 1);
            if (methodInfo != null)
            {
                var args = new List<object>
                {
                    caller
                };

                if (parameters.IsNotNullOrEmpty())
                {
                    args.AddRange(parameters);
                }

                var returnValue = methodInfo.MakeGenericMethod(genericTypes).Invoke(caller, args.ToArray());
                if (returnValue != null)
                {
                    return (T)returnValue;
                }
            }

            return default;
        }

        /// <summary>
        /// 判断成员中是否包含特性
        /// </summary>
        /// <typeparam name="T">类型参数, Attribute 类型</typeparam>
        /// <param name="member">带判断成员</param>
        /// <param name="inherit">是否包含继承的特性</param>
        /// <returns>判断结果</returns>
        public static bool HasAttribute<T>(this MemberInfo member, bool inherit = true) where T : Attribute => member.IsDefined(typeof(T), inherit);
        /// <summary>
        /// 获取成员特性的指定属性值
        /// </summary>
        /// <param name="member">待获取对象</param>
        /// <param name="propertyName">用于获取值的特性上的属性名称</param>
        /// <returns>显示名称</returns>
        public static TValue? GetAttributeValue<TAttribute, TValue>(this MemberInfo member, string propertyName) where TAttribute : Attribute
        {
            var result = member?.GetCustomAttribute<TAttribute>()?.GetPropertyValue(propertyName);
            return result == null ? default : (TValue)result;
        }

        /// <summary>
        /// 获取属性上设置的 excel 特性内容
        /// </summary>
        /// <param name="propertyInfo"></param>
        /// <returns></returns>
        public static ExcelAttribute? GetExcelAttribute(this MemberInfo memberInfo)
        {
            if (memberInfo == null || !(memberInfo.MemberType == MemberTypes.Property || memberInfo.MemberType == MemberTypes.Field))
            {
                throw new ArgumentException("成员类型只能是属性或者字段, 且不可为空!", nameof(memberInfo));
            }

            var attribute = memberInfo.GetCustomAttribute<ExcelAttribute>(true);
            if (attribute == null)
            {
                attribute = new ExcelAttribute();
            }

            attribute.Field ??= memberInfo;
            var name = memberInfo.GetAttributeValue<DisplayAttribute, string>(nameof(DisplayAttribute.Name))
                ?? memberInfo.GetAttributeValue<DisplayNameAttribute, string>(nameof(DisplayNameAttribute.DisplayName))
                ?? memberInfo.GetAttributeValue<DescriptionAttribute, string>(nameof(DescriptionAttribute.Description));
            attribute.Name ??= name ?? attribute.Field.Name;
            attribute.FieldType = memberInfo.GetMemberType();
            attribute.Required = (attribute.FieldType != null && (!attribute.FieldType.IsNullable())) || memberInfo.HasAttribute<RequiredAttribute>();
            attribute.FieldType = attribute.FieldType?.GetCoreType();

            switch (Type.GetTypeCode(attribute.FieldType))
            {
                case TypeCode.DateTime:
                    attribute.Format ??= AppSettings.DEFAULT_DATETIME_FORMAT;
                    attribute.Size = attribute.Size <= 0 ? AppSettings.DEFAULT_EXCEL_DATETIME_SIZE : attribute.Size;
                    break;
                case TypeCode.Byte:
                case TypeCode.SByte:
                case TypeCode.UInt16:
                case TypeCode.Int16:
                case TypeCode.UInt32:
                case TypeCode.Int32:
                case TypeCode.UInt64:
                case TypeCode.Int64:
                    attribute.Format ??= AppSettings.DEFAULT_EXCEL_NUMBER_FORMAT;
                    attribute.Size = attribute.Size <= 0 ? AppSettings.DEFAULT_EXCEL_NUMBER_SIZE : attribute.Size;
                    break;
                case TypeCode.Single:
                case TypeCode.Double:
                case TypeCode.Decimal:
                    attribute.Format ??= AppSettings.DEFAULT_EXCEL_DOUBLE_FORMAT;
                    attribute.Size = attribute.Size <= 0 ? AppSettings.DEFAULT_EXCEL_DOUBLE_SIZE : attribute.Size;
                    break;
                case TypeCode.Empty:
                case TypeCode.Boolean:
                case TypeCode.Char:
                    attribute.Format ??= AppSettings.DEFAULT_EXCEL_STRING_FORMAT;
                    attribute.Size = attribute.Size <= 0 ? AppSettings.DEFAULT_EXCEL_NUMBER_SIZE : attribute.Size;
                    break;
                case TypeCode.DBNull:
                case TypeCode.Object:
                case TypeCode.String:
                default:
                    attribute.Format ??= AppSettings.DEFAULT_EXCEL_STRING_FORMAT;
                    attribute.Size = attribute.Size <= 0 ? AppSettings.DEFAULT_EXCEL_STRING_SIZE : attribute.Size;
                    attribute.MaxLength = memberInfo.GetCustomAttribute<MaxLengthAttribute>()?.Length ?? 0;
                    break;
            }

            return attribute;
        }

        /// <summary>
        /// 获取属性或字段的 field 描述
        /// </summary>
        /// <param name="memberInfo"></param>
        /// <returns></returns>
        public static FieldAttribute GetFieldAttribute(this MemberInfo memberInfo)
        {
            var attribute = memberInfo.GetCustomAttribute<FieldAttribute>(true) ?? new FieldAttribute();
            attribute.Name ??= memberInfo.Name;
            attribute.Doc ??= memberInfo.GetDisplayName();
            if (attribute.Type == TypeCode.Empty)
            {
                attribute.Type = Type.GetTypeCode(memberInfo.DeclaringType);
            }

            attribute.Size = attribute.Type switch
            {
                TypeCode.Boolean or TypeCode.Byte or TypeCode.SByte => 1,
                TypeCode.Char or TypeCode.Int16 or TypeCode.UInt16 => 2,
                TypeCode.Int32 or TypeCode.UInt32 or TypeCode.Single => 4,
                TypeCode.Int64 or TypeCode.UInt64 or TypeCode.Double or TypeCode.Decimal => 8,
                _ => attribute.Size
            };

            return attribute;
        }
        /// <summary>
        /// 获取类型的所有字段 field 特性值
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static ICollection<FieldAttribute>? GetFieldAttributes(this Type type) => type?.GetMembers().Where(x => x.HasAttribute<FieldAttribute>()).Select(x => x.GetFieldAttribute()).ToList();
    }
}
